﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Beacon.SPC;

namespace Beacon.Test
{
    public class RuleTester
    {
        #region RULE TEST
        public static void test()
        {
            //TestQueue();
            TestWERule1();
            TestWERule2();
            TestWERule3();
            TestWERule4();
            TestTrend();
            TestOscillation();
            TestStratification();
            TestMixture();
            TestRules();
        }

        /// <summary>
        /// test spc data queue.
        /// </summary>
        private static void TestQueue()
        {
            SpcDataQueue q = new SpcDataQueue(3);
            System.Random r = new System.Random(DateTime.Now.Millisecond);
            for (int i = 0; i < 20; i++)
            {
                double d = r.Next(0, 100);
                Console.WriteLine("enqueue value : {0}", d);
                q.Enqueue(d);
                q.PrintConsole();
            }
        }

        /// <summary>
        /// test we rule 1
        /// </summary>
        private static void TestWERule1()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test WERule1 ");
            Console.WriteLine("-------------------");
            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.WERule1, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 8.0, true);
            CheckValue(meanRule, 12.0, true);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test WERule1 finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule 2
        /// </summary>
        private static void TestWERule2()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test WERule2 ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.WERule2, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 11.1, true); // 11.5 and 11.1

            CheckValue(meanRule, 12.0, false);
            CheckValue(meanRule, 12.0, true); // 12.0 and 12.0

            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.9, true); // 8.5 and 8.9 

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test WERule2 finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule 3
        /// </summary>
        private static void TestWERule3()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test WERule3 ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.WERule3, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            // 4 out of 5 upper/lower than one-sigma line
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, true); // 11.5, 11.1, 10.6 and 10.7

            CheckValue(meanRule, 12.0, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.4, true); // 8.5, 8.9, 9.0 and 9.4

            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 11.1, false);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test WERule3 finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule 4
        /// </summary>
        private static void TestWERule4()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test WERule4 ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.WERule4, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            //9 consecutive points fall on the same side of the centerline (in zone C or beyond).
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 12.0, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 12.0, true); //... 

            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.41, false);
            CheckValue(meanRule, 9.42, false);
            CheckValue(meanRule, 9.43, false);
            CheckValue(meanRule, 9.44, true);// ...

            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.7, false);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test WERule4 finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule trend
        /// </summary>
        private static void TestTrend()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test Trend ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.Trend, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            //7 or more consecutive points without a change in direction.
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 11.6, false);
            CheckValue(meanRule, 12.7, true);

            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.0, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 9.9, false);
            CheckValue(meanRule, 10.0, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.1, true);

            CheckValue(meanRule, 12.6, false);
            CheckValue(meanRule, 11.8, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 9.6, false);
            CheckValue(meanRule, 9.54, true);

            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.7, false);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test Trend finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule Oscillation
        /// </summary>
        private static void TestOscillation()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test Oscillation ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.Oscillation, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            //14 or more consecutive points alternate in direction.
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 10.5, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 9.1, false);
            CheckValue(meanRule, 11.6, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.8, true);

            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.0, false);
            CheckValue(meanRule, 9.0, false);

            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 9.9, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 12.6, false);
            CheckValue(meanRule, 11.8, false);
            CheckValue(meanRule, 11.9, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 9.6, false);
            CheckValue(meanRule, 9.64, false);
            CheckValue(meanRule, 9.5, false);
            CheckValue(meanRule, 11.4, false);
            CheckValue(meanRule, 11.1, false);
            CheckValue(meanRule, 11.7, false);
            CheckValue(meanRule, 10.7, false);
            CheckValue(meanRule, 11.7, true);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test Oscillation finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule Oscillation
        /// </summary>
        private static void TestStratification()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test Stratification ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.Stratification, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            //15 or more consecutive points fall inside 1σ zone.
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 11.5, false);

            CheckValue(meanRule, 9.89, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.5, false);
            CheckValue(meanRule, 9.78, false);
            CheckValue(meanRule, 10.0, false);
            CheckValue(meanRule, 9.56, false);
            CheckValue(meanRule, 9.5, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.0, false);
            CheckValue(meanRule, 10.5, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 10.0, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 9.5, true);

            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 13.5, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 9.0, false);
            CheckValue(meanRule, 9.41, false);
            CheckValue(meanRule, 9.42, false);
            CheckValue(meanRule, 9.43, false);
            CheckValue(meanRule, 9.34, false);

            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 9.8, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.23, false);
            CheckValue(meanRule, 10.45, false);
            CheckValue(meanRule, 9.55, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.23, false);
            CheckValue(meanRule, 10.45, false);
            CheckValue(meanRule, 9.55, true);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test Stratification finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test we rule Oscillation
        /// </summary>
        private static void TestMixture()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test Mixture ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            ISpcRule meanRule = SpcRuleFactory.CreateRule(SpcRules.Mixture, MeanLimit, SpcControlSide.Both);
            Console.WriteLine("Rule {0} created.", meanRule.RuleType());

            ConsoleColor bakColor = Console.ForegroundColor;

            //8 or more consecutive points fall outside 1σ zone and on both sides.
            CheckValue(meanRule, 10.2, false);
            CheckValue(meanRule, 9.5, false);

            CheckValue(meanRule, 9.32, false);
            CheckValue(meanRule, 10.8, false);
            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 8.78, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 8.56, false);
            CheckValue(meanRule, 9.21, true);

            CheckValue(meanRule, 11.4, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 11.5, false);
            CheckValue(meanRule, 11.8, false);
            CheckValue(meanRule, 11.0, false);
            CheckValue(meanRule, 11.4, false);
            CheckValue(meanRule, 12.5, false);

            CheckValue(meanRule, 10.3, false);

            CheckValue(meanRule, 8.0, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 8.5, false);
            CheckValue(meanRule, 8.9, false);
            CheckValue(meanRule, 8.0, false);
            CheckValue(meanRule, 8.4, false);
            CheckValue(meanRule, 9.4, false);
            CheckValue(meanRule, 9.0, false);

            CheckValue(meanRule, 9.51, false);

            CheckValue(meanRule, 9.41, false);
            CheckValue(meanRule, 9.42, false);
            CheckValue(meanRule, 9.43, false);
            CheckValue(meanRule, 9.34, false);
            CheckValue(meanRule, 10.6, false);
            CheckValue(meanRule, 9.34, false);
            CheckValue(meanRule, 9.45, false);
            CheckValue(meanRule, 10.54, true);

            CheckValue(meanRule, 10.1, false);
            CheckValue(meanRule, 10.23, false);
            CheckValue(meanRule, 10.45, false);
            CheckValue(meanRule, 9.55, false);
            CheckValue(meanRule, 10.4, false);
            CheckValue(meanRule, 10.1, false);

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Test Mixture finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// test all rules
        /// </summary>
        private static void TestRules()
        {
            Console.WriteLine("-------------------");
            Console.WriteLine(" Test All Rules With Random Number ");
            Console.WriteLine("-------------------");

            SpcControlLimit MeanLimit = new SpcControlLimit(SpcChartType.XBarR, SpcDataType.Mean, 10, 0.5, 3);
            //Console.WriteLine(MeanLimit.ToString());

            Dictionary<string, int> summary = new Dictionary<string, int>();
            List<ISpcRule> rules = new List<ISpcRule>();
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.WERule1, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.WERule2, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.WERule3, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.WERule4, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.Trend, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.Oscillation, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.Stratification, MeanLimit, SpcControlSide.Both));
            rules.Add(SpcRuleFactory.CreateRule(SpcRules.Mixture, MeanLimit, SpcControlSide.Both));

            Console.WriteLine("Rule list created:");
            foreach (ISpcRule r in rules)
            {
                Console.WriteLine(r.RuleType().ToString());
            }

            List<double> rawData = new List<double>();
            System.Random source = new System.Random(DateTime.Now.Millisecond);
            for (int i = 0; i < 10000; i++)
            {
                double r = 0;
                for (int j = 0; j < 5; j++)
                {
                    r += source.Next(8, 12);
                }
                rawData.Add(r / 5);
            }

            ConsoleColor bakColor = Console.ForegroundColor;
            foreach (double d in rawData)
            {

                foreach (ISpcRule r in rules)
                {
                    if (r.AddPoint(d))
                    {
                        if (!summary.ContainsKey(r.RuleType().ToString()))
                            summary[r.RuleType().ToString()] = 1;
                        else
                            summary[r.RuleType().ToString()]++;
                    }
                }
            }

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("-------------------");
            Console.WriteLine("summary");
            Console.WriteLine("-------------------");

            foreach (string s in summary.Keys)
            {
                Console.WriteLine("rule {0} violated {1} times.", s, summary[s]);
            }

            Console.WriteLine("test rules finished.");
            Console.ForegroundColor = bakColor;
        }

        /// <summary>
        /// add value to a spc rule,
        /// if expected is ture, but rule not outputs a violate, show warning message.
        /// if expected is false, but rule outputs a violate, show warning message.
        /// </summary>
        /// <param name="r"></param>
        /// <param name="v"></param>
        /// <param name="expected"></param>
        public static void CheckValue(ISpcRule r, double v, bool expected)
        {
            if (expected && !r.AddPoint(v))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("point value {0} should violated rule", v);
                Console.ReadLine();
            }
            else if (!expected && r.AddPoint(v))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("point value {0} should not violated rule", v);
                Console.ReadLine();
            }
        }

        #endregion
    }
}
